/*

    functions.cpp - a collection of mono-objective test functions
    Author Julio Agustin Barrera Mendoza
    Copyright (C) 2009 CINVESTAV-IPN.

    This program is free software; you can redistribute it and/or modify it 
    under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2 of the License, 
    or (at your option) any later version.

    This program is distributed in the hope that it will be useful, 
    but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
    FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along with this program; 
    if not, write to the Free Software Foundation, Inc., 59 Temple Place, 
    Suite 330, Boston, MA 02111-1307 USA

 */

#include "functions.h"

// ------------------------------------------------------------------
// FUNCTION sphere
// ------------------------------------------------------------------

long double sphere(const Array &value)
{
  unsigned int i, variables = value.size();
  long double result = 0.0;
  
  for (i = 0; i < variables; i++)
    result += value[i] * value[i];
  
  return result;
}

// ------------------------------------------------------------------
// FUNCTION schwefelOne
// ------------------------------------------------------------------

long double schwefelOne(const Array &value)
{
  unsigned int i, j, variables = value.size();
  long double result = 0.0, partialResult;
  
  for (i = 0; i < variables; i++)
    {
      partialResult = 0.0;
      for (j = 0; j <= i; j++)
        partialResult += value[j];
      result += partialResult * partialResult;
    }
  
  return result;
}

// ------------------------------------------------------------------
// FUNCTION rosenbrock
// ------------------------------------------------------------------

long double rosenbrock(const Array &value)
{
  unsigned int i, variables = value.size();
  unsigned int limit = variables - 1;
  long double result = 0.0;
  
  for (i = 0; i < limit; i++)
    result += 100.0 * (value[i + 1] - value[i] * value[i]) * (value[i + 1] - value[i] * value[i]) + (value[i] - 1.0) * (value[i] - 1.0);
    
  return result;
}

// ------------------------------------------------------------------
// FUNCTION schwefelTwo
// ------------------------------------------------------------------

long double schwefelTwo(const Array &value)
{
  unsigned int i, variables = value.size();
  long double result = 0.0;
  
  for (i = 0; i < variables; i++)
    result += value[i] * sinl(sqrtl(fabsl(value[i])));

  result = 418.9829 * variables - result;
  
  return result;
}

// ------------------------------------------------------------------
// FUNCTION rastrigin
// ------------------------------------------------------------------

long double rastrigin(const Array &value)
{
  unsigned int i, variables = value.size();
  long double result = 0.0;
  
  for (i = 0; i < variables; i++)
    result += value[i] * value[i] - 10.0 * cosl(2.0 * 3.14159265358979323846 * value[i]) + 10.0;
  
  return result;
}

// ------------------------------------------------------------------
// FUNCTION ackley
// ------------------------------------------------------------------

long double ackley(const Array &value)
{
  unsigned int i, variables = value.size();
  long double firstSum = 0.0, secondSum = 0.0, result;
  
  for (i = 0; i < variables; i++)
    {
      firstSum += value[i] * value[i];
      secondSum += cosl(2.0 * 3.14159265358979323846 * value[i]);
    }

  firstSum /= variables;
  firstSum = -0.2 * sqrtl(firstSum);
  
  secondSum /= variables;

  result = -20.0 * expl(firstSum) - expl(secondSum) + expl(1.0) + 20.0;

  return result;
}

// ------------------------------------------------------------------
// FUNCTION griewank
// ------------------------------------------------------------------

long double griewank(const Array &value)
{
  unsigned int i, variables = value.size();
  long double sum = 0.0, product = 1.0, result;
  
  for (i = 0; i < variables; i++)
    {
      sum += value[i] * value[i];
      product *= cosl(value[i] / sqrtl(i + 1.0));
    }

  sum /= 4000.0;
  
  result = sum - product + 1.0;

  return result;
}

// ------------------------------------------------------------------
// FUNCTION schafferf6
// ------------------------------------------------------------------

long double schafferf6(const Array &value)
{
  long double result = 0.0;
  long double x = value[0];
  long double y = value[1];
  long double numerator = 0.0, denominator = 0.0;
  
  numerator = sinl(sqrtl(x*x + y*y)) * sinl(sqrtl(x*x + y*y)) - 0.5;
  denominator = (1.0 + 0.001 * (x*x + y*y)) * (1.0 + 0.001 * (x*x + y*y));

  result = 0.5  + numerator / denominator;

  return result;
}

// ------------------------------------------------------------------
// FUNCTION debOne
// ------------------------------------------------------------------

long double debOne(const Array &value)
{
  long double result = 0.0;
  
  result = sinl(5.0 * PI * value[0]);
  result = powl(result, 6.0);
  
  return result;
}

// ------------------------------------------------------------------
// FUNCTION debTwo
// ------------------------------------------------------------------

long double debTwo(const Array &value)
{
  long double result = 0.0;
  
  result = powl((value[0] - 0.1) * 1.25, 2.0);
  result *= -2.0 * logl(2.0);
  result = expl(result);
  result *= powl(sinl(5.0 * PI * value[0]), 6.0);
  
  return result;
}

// ------------------------------------------------------------------
// FUNCTION debThree
// ------------------------------------------------------------------

long double debThree(const Array &value)
{
  long double result = 0.0;
  
  result = sinl(5.0 * PI * (powl(value[0], 0.75) - 0.05));
  result = powl(result, 6.0);
  
  return result;
}

// ------------------------------------------------------------------
// FUNCTION debFour
// ------------------------------------------------------------------

long double debFour(const Array &value)
{
  long double result = 0.0;
  
  result = powl((value[0] - 0.08) / 0.854, 2.0);
  result *= -2.0 * logl(2.0);
  result = expl(result);
  result *= powl(sinl(5.0 * PI * (powl(value[0], 0.75) - 0.05)), 6.0);

  return result;
}

// ------------------------------------------------------------------
// FUNCTION himmelblau
// ------------------------------------------------------------------

long double himmelblau(const Array &value)
{
  long double result = 0.0;
  
  result = 200.0;
  result -= powl(value[0] * value[0] + value[1] - 11.0, 2.0);
  result -= powl(value[0] + value[1] * value[1] - 7.0, 2.0);
  
  return result;
}

// ------------------------------------------------------------------
// FUNCTION branin
// ------------------------------------------------------------------

long double branin(const Array &value)
{
  long double result = 0.0;
  
  result = 10.0;
  result += 10.0 * (1.0 - 1.0 / (8.0 * PI)) * cosl(value[0]);
  result += powl(value[1] - 5.1 * value[0] * value[0] / (4.0 * PI * PI)
                 + 5.0 * value[0] / PI - 6.0, 2.0);
                 
  return result;
}

// ------------------------------------------------------------------
// FUNCTION camelBack
// ------------------------------------------------------------------

long double camelBack(const Array &value)
{
  long double result = 0.0, first = 0.0, second = 0.0;
  
  first = 4.0 - 2.1 * value[0] * value[0] + powl(value[0], 4.0) / 3.0;
  second = -4.0 + 4.0 * value[1] * value[1];
  result = first * value[0] * value[0] + value[0] * value[1] + second * value[1] * value[1];
  result *= -4.0;

  return result;
}

// ------------------------------------------------------------------
// FUNCTION shubert
// ------------------------------------------------------------------

long double shubert(const Array &value)
{
  unsigned int i;
  long double result = 0.0, first = 0.0, second = 0.0;
  
  for (i = 1; i < 6; i++)
    first += i * cosl((i + 1.0) * value[0] + i);
    
  for (i = 1; i < 6; i++)
    second += i * cosl((i + 1.0) * value[1] + i);

  result = first * second;
  
  return result;
}

// ------------------------------------------------------------------
// FUNCTION vincent
// ------------------------------------------------------------------

long double vincent(const Array &value)
{
  unsigned int i, variables = value.size();
  long double result = 0.0;
  
  for (i = 0; i < variables; i++)
    result += sinl(10.0 * logl(value[i]));

  result *= - 1.0 / variables;
  
  return result;
}

// ------------------------------------------------------------------
// FUNCTION twoPeakTrap
// ------------------------------------------------------------------

long double twoPeakTrap(const Array &value)
{
  long double result = 0.0;
  
  if (0.0 <= value[0] && value[0] < 15.0)
    result = 160.0 / 15.0 * (15.0 - value[0]);
  else if (15.0 <= value[0] && value[0] <= 20.0)
    result = 200.0 / 5.0 * (value[0] - 15.0);
    
  return result;
}

// ------------------------------------------------------------------
// FUNCTION twoPeakCentral
// ------------------------------------------------------------------

long double twoPeakCentral(const Array &value)
{
  long double result = 0.0;
  
  if (0.0 <= value[0] && value[0] < 10.0)
    result = 160.0 / 10.0 * value[0];
  else if (10.0 <= value[0] && value[0] < 15.0)
    result = 160.0 / 5.0 * (15.0 - value[0]);
  else if (15.0 <= value[0] && value[0] <= 20.0)
    result = 200.0 / 5.0 * (value[0] - 15.0);
    
  return result;
}

// ------------------------------------------------------------------
// FUNCTION fivePeakTrap
// ------------------------------------------------------------------

long double fivePeakTrap(const Array &value)
{
  long double result = 0.0;
  
  if (0.0 <= value[0] && value[0] < 2.5)
    result = 80.0 * (2.5 - value[0]);
  else if (2.5 <= value[0] && value[0] < 5.0)
    result = 64.0 * (value[0] - 2.5);
  else if (5.0 <= value[0] && value[0] < 7.5)
    result = 64.0 * (7.5 - value[0]);
  else if (7.5 <= value[0] && value[0] < 12.5)
    result = 28.0 * (value[0] - 7.5);
  else if (12.5 <= value[0] && value[0] < 17.5)
    result = 28.0 * (17.5 - value[0]);
  else if (17.5 <= value[0] && value[0] < 22.5)
    result = 32.0 * (value[0] - 17.5);
  else if (22.5 <= value[0] && value[0] < 27.5)
    result = 32.0 * (27.5 - value[0]);
  else if (27.5 <= value[0] && value[0] <= 30.0)
    result = 80.0 * (value[0] - 27.5);

  return result;
}

// ------------------------------------------------------------------
// FUNCTION foxholes
// ------------------------------------------------------------------

long double foxholes(const Array &value)
{
  unsigned int i;
  long double result = 0.0;
  
  for (i = 0; i < 25; i++)
    result += 1.0 / (1.0 + i + powl(value[0] - 16 * (i % 5) - 2.0, 6.0)
                             + powl(value[1] - 16 * floorl(i / 5.0) - 2.0, 6.0));
  
  result += 0.002;
  result = 500.0 - 1.0 / result;

  return result;
}






